package com.idanchuang.component.config.apollo;

import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.Config;
import com.idanchuang.component.config.apollo.config.ApolloConfigBean;
import com.idanchuang.spi.config.ConfigChangeListener;
import com.idanchuang.spi.config.ConfigChangeWithKeysListener;
import com.idanchuang.spi.config.IConfig;

import java.util.*;

/**
 * @author yjy
 * @date 2019/11/8 10:42
 **/
public class ConfigService implements IConfig {

    private ApolloConfigBean apolloConfigBean;
    private List<Config> configs;

    public ConfigService(ApolloConfigBean apolloConfigBean) {
        this.apolloConfigBean = apolloConfigBean;
        this.configs = new ArrayList<>();
        for (String namespace : this.apolloConfigBean.getNamespacesList()) {
            configs.add(com.ctrip.framework.apollo.ConfigService.getConfig(namespace));
        }
    }

    @Override
    public Set<String> getKeys() {
        Set<String> keys = new HashSet<>();
        for (Config config : configs) {
            keys.addAll(config.getPropertyNames());
        }
        return keys;
    }

    @Override
    public Map<String, Object> getAll() {
        Map<String, Object> allConfig = new HashMap<>(32);
        for (Config config : configs) {
            Set<String> keys = config.getPropertyNames();
            for (String key : keys) {
                allConfig.put(key, config.getProperty(key, null));
            }
        }
        return allConfig;
    }

    @Override
    public String getString(String key, String defaultValue) {
        return getFromConfigs((config) -> config.getProperty(key, null), defaultValue);
    }

    @Override
    public Integer getInteger(String key, Integer defaultValue) {
        return getFromConfigs((config) -> config.getIntProperty(key, null), defaultValue);
    }

    @Override
    public Short getShort(String key, Short defaultValue) {
        return getFromConfigs((config) -> config.getShortProperty(key, null), defaultValue);
    }

    @Override
    public Byte getByte(String key, Byte defaultValue) {
        return getFromConfigs((config) -> config.getByteProperty(key, null), defaultValue);
    }

    @Override
    public Long getLong(String key, Long defaultValue) {
        return getFromConfigs((config) -> config.getLongProperty(key, null), defaultValue);
    }

    @Override
    public Float getFloat(String key, Float defaultValue) {
        return getFromConfigs((config) -> config.getFloatProperty(key, null), defaultValue);
    }

    @Override
    public Double getDouble(String key, Double defaultValue) {
        return getFromConfigs((config) -> config.getDoubleProperty(key, null), defaultValue);
    }

    @Override
    public Boolean getBoolean(String key, Boolean defaultValue) {
        return getFromConfigs((config) -> config.getBooleanProperty(key, null), defaultValue);
    }

    @Override
    public String[] getStringArray(String key, String... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, String.class).toArray(new String[]{});
    }

    @Override
    public Integer[] getIntegerArray(String key, Integer... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Integer.class).toArray(new Integer[]{});
    }

    @Override
    public Short[] getShortArray(String key, Short... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Short.class).toArray(new Short[]{});
    }

    @Override
    public Byte[] getShortArray(String key, Byte... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Byte.class).toArray(new Byte[]{});
    }

    @Override
    public Long[] getLongArray(String key, Long... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Long.class).toArray(new Long[]{});
    }

    @Override
    public Double[] getDoubleArray(String key, Double... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Double.class).toArray(new Double[]{});
    }

    @Override
    public Float[] getFloatArray(String key, Float... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Float.class).toArray(new Float[]{});
    }

    @Override
    public Boolean[] getBooleanArray(String key, Boolean... defaultValues) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return defaultValues;
        }
        return JSON.parseArray(val, Boolean.class).toArray(new Boolean[]{});
    }

    @Override
    public Date getDate(String key, Date defaultValue) {
        return getFromConfigs((config) -> config.getDateProperty(key, null), defaultValue);
    }

    @Override
    public Date getDate(String key, String format, Date defaultValue) {
        return getFromConfigs((config) -> config.getDateProperty(key, format,null), defaultValue);
    }

    @Override
    public Date getDate(String key, String format, Locale locale, Date defaultValue) {
        return getFromConfigs((config) -> config.getDateProperty(key, format, locale, null), defaultValue);
    }

    @Override
    public Map<String, Object> getMap(String key) {
        String val = getFromConfigs((config) -> config.getProperty(key, null), null);
        if (val == null) {
            return null;
        }
        return JSON.parseObject(val);
    }

    @Override
    public void addChangeListener(ConfigChangeListener listener) {
        for (Config config : configs) {
            config.addChangeListener((changeEvent) -> listener.onChange());
        }
    }

    @Override
    public void addChangeListener(ConfigChangeWithKeysListener listener) {
        for (Config config : configs) {
            config.addChangeListener((changeEvent) -> listener.onChange(changeEvent.changedKeys()));
        }
    }

    private <T> T getFromConfigs(Getter<T> getter, T defaultValue) {
        T value = null;
        for (Config config : configs) {
            value = getter.get(config);
            if (value != null) {
                break;
            }
        }
        return value == null ? defaultValue : value;
    }

    public ApolloConfigBean getApolloConfigBean() {
        return apolloConfigBean;
    }

    public void setApolloConfigBean(ApolloConfigBean apolloConfigBean) {
        this.apolloConfigBean = apolloConfigBean;
    }

    @FunctionalInterface
    private interface Getter<T> {

        T get(Config config);

    }

}
